/*
 * Copyright 2024 The CHANGLEI Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'dart:io';

import 'package:fibber/src/logger.dart';
import 'package:fibber/src/name.dart';
import 'package:fibber/src/spec.dart';
import 'package:fibber/src/svg2ttf/npm.dart';
import 'package:fibber/src/svg2ttf/yaml.dart';
import 'package:fibber/src/writer.dart';
import 'package:path/path.dart' as path;

final _classnameGenerator = NameGenerator();

Future<void> resolve(String input, String output, String ttfOutput, String classname, String? fontPackage) async {
  final pubspecFile = File(path.join(r'pubspec.yaml'));
  if (!pubspecFile.existsSync()) {
    Level.error.writeln(r'未发现`pubspec.yaml`，请在项目根目录执行');
    return;
  }
  final inputDirectory = Directory(input);
  if (!inputDirectory.existsSync()) {
    Level.error.writeln('文件夹`$input`不存在');
    return;
  }
  final name = _classnameGenerator.classOf(classname);
  final specs = await _toSpecs(input, ttfOutput, name, fontPackage).toList();
  if (specs.isEmpty) {
    return;
  }
  writeSpecsFile(
    output,
    name,
    specs..sort(),
    imports: [
      const Import(
        r'package:flutter/widgets.dart',
        show: [
          r'IconData',
        ],
      ),
    ],
  );

  await writePubspecYaml(pubspecFile, ttfOutput, name);
}

Stream<NameSpec> _toSpecs(String input, String ttfOutput, Name classname, String? fontPackage) async* {
  final icons = await generateTTF(input, ttfOutput, classname);
  if (icons == null) {
    return;
  }
  final fieldNameGenerator = NameGenerator();
  final fontFamilyField = StaticField(
    name: r'_fontFamily'.named,
    type: Name.string,
    doc: r'fontFamily',
    constructor: "r'${classname.titleCased}'",
  );
  StaticField? fontPackageField;
  if (fontPackage != null) {
    fontPackageField = StaticField(
      name: r'_fontPackage'.named,
      type: Name.string,
      doc: 'fontPackage',
      constructor: "'$fontPackage'",
    );
  }
  final fields = <Field>[];
  for (final MapEntry(key: key, value: value) in icons.entries) {
    final filepath = path.setExtension(path.posix.joinAll([input, ...key.split(r'-')]), r'.svg');
    final codePoint = '0x${value.toRadixString(16)}';
    final fieldName = fieldNameGenerator.fieldOf(key);
    if (fieldName.isEmpty) {
      continue;
    }
    fields.add(
      IconDataField(
        name: fieldName,
        path: filepath,
        codePoint: codePoint,
        fontFamily: fontFamilyField.name,
        fontPackage: fontPackageField?.name,
      ),
    );
  }

  fields.sort();
  fields.insert(0, fontFamilyField);
  if (fontPackageField != null) {
    fields.insert(1, fontPackageField);
  }

  if (fields.isNotEmpty) {
    yield Class(
      name: classname,
      path: input,
      fields: fields,
    );
  }
}
